/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package fr.loof.fonzie.keywords;


import java.util.List;

import fr.loof.fonzie.parsers.Constraint;
import fr.loof.fonzie.parsers.JPQLPersistenceQuery;
import fr.loof.fonzie.parsers.KeyWord;

public abstract class AbstractConstraint
    extends KeyWord
    implements Constraint
{

    private String operator;

    public AbstractConstraint( String operator )
    {
        this.operator = operator;
    }

    public final void process( JPQLPersistenceQuery query, List<Class> params )
    {
        String property = query.getCurrentProperty();
        Class propertyType = checkFieldExists( query.getCurrentEntity(), property );

        query.append( " " ).append( operator );
        declareParameters( query, params, property, propertyType );
    }

    /**
     * Can be overriden to declare less or more parameters
     */
    protected void declareParameters( JPQLPersistenceQuery query, List<Class> params, String property, Class type )
    {
        declareParameter( query, params, property, type );
    }

    protected final void declareParameter( JPQLPersistenceQuery query, List<Class> params, String param, Class type )
    {
        query.append( " :" ).append( param );
        query.add( param, type );

        Class arg = params.remove( 0 );
        checkParameterType( query.getCurrentEntity(), param, type, arg );
    }

    protected void checkParameterType( Class entity, String property, Class propertyType, Class arg )
    {
        if ( !arg.isAssignableFrom( propertyType ) )
        {
            throw new IllegalStateException( "Constraint on " + entity.getSimpleName() + "." + property + " ("
                + propertyType.getSimpleName() + ") is not compatible with parameter type " + arg );
        }
    }
}